feat(v2): land agent-core-v2 engine and kap-server behind experimental flag#1441
feat(v2): land agent-core-v2 engine and kap-server behind experimental flag#1441sailist wants to merge 563 commits into
Conversation
🦋 Changeset detectedLatest commit: f8ebe5b The changes in this PR will be included in the next version bump. This PR includes changesets to release 6 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fbb4a3a0c6
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| const session = this.opts.core.accessor.get(ISessionLifecycleService).get(sessionId); | ||
| if (session === undefined) return undefined; |
There was a problem hiding this comment.
Resume cold sessions before accepting WS subscriptions
When a client reconnects to a session that exists only on disk, such as after a server-v2 restart, the default snapshot path can succeed via the disk reader without materializing the session in ISessionLifecycleService. The following /api/v1/ws subscribe then calls ensureState, but this get() only checks live sessions and returns undefined, so the subscribe ack reports not_found and the socket is never registered; if a later prompt request resumes the session, that client still receives no live turn events. Use resume() here or otherwise create a broadcaster state for cold persisted sessions before returning false.
Useful? React with 👍 / 👎.
| 'file.not_found', | ||
| 'file.too_large', | ||
| 'fs.path_not_found', | ||
| 'fs.permission_denied', | ||
| 'validation.failed', |
There was a problem hiding this comment.
Keep the Kimi error schema exhaustive
The KimiErrorCode union above includes additional codes such as prompt.not_found, session.busy, fs.path_escapes, fs.is_directory, fs.is_binary, fs.too_large, fs.already_exists, fs.too_many_results, fs.grep_timeout, and fs.git_unavailable, but this runtime z.enum omits them. Any error or turn.ended.error payload carrying one of those valid codes from agent-core-v2 will fail eventSchema / sessionEventMessageSchema validation even though the TypeScript type says it is valid, so add the missing literals or derive the schema from a single source.
Useful? React with 👍 / 👎.
|
❌ Nix build failed Hash mismatch in
Please update |
…into kimi-code-v2
When the Kimi OAuth toolkit short-circuits via its `ensureFresh` fast path (the cached refresh token is still usable), `toolkit.login` resolves without firing `onDeviceCode`. The v2 `OAuthService.startLogin` previously rejected in this case, so `POST /api/v1/oauth/login` returned a 500 that the web client swallowed and mislabeled as "current daemon does not support login". CLI-authenticated users could not (re)enter the v2 daemon through the web UI. Treat that path as already authenticated: provision the managed provider (idempotent), refresh OAuth provider models so `defaultModel` is seeded (`/auth` then reports ready, matching v1 parity), and return a new `status: 'authenticated'` `OAuthFlowStart` variant so the web LoginDialog can skip the device-code UI entirely instead of falling into its catch-all "unsupported daemon" state. The protocol `OAuthFlowStart` schema is now a discriminated union on `status`; kimi-web's wire / composable / LoginDialog types are updated to handle the new `authenticated` branch. Tests: updated the v2 OAuthService test that previously asserted the buggy rejection to instead assert the fast path returns authenticated and provisions the provider.
…into kimi-code-v2
Move MicroCompactionEffect next to the service that produces it, and derive MicroCompactionConfig from the single zod schema in configSection.ts so the section schema and the runtime config type no longer drift.
Run SubagentStart/SubagentStop and SessionStart/SessionEnd external hooks by observing hook slots instead of being invoked directly, matching the other external-hook observers. - Add Agent-scoped IAgentRunHooksService hosting onWillStartAgentTask / onDidStopAgentTask; mirrorAgentRun runs those slots rather than calling IAgentExternalHooksService directly. - AgentExternalHooksService registers on those slots to emit SubagentStart/SubagentStop; drop runAgentTaskStart/notifyAgentTaskStop from its public interface. - Add Session-scoped ISessionExternalHooksService. ISessionLifecycleService gains onDidCreateSession / onWillCloseSession slots announcing source/reason for create, resume, fork, close, archive. - Move externalHooks from L5 to L6 in check-domain-layers.mjs, update the DI dependency map, and drop now-dead Hooks/OrderedHookSlot/@IAgentTurnService imports.
…fresh OAuthService.invalidateFlows previously cleared every in-flight device-code login on any provider config change. Startup-time model catalog refreshes rewrite the providers section without changing the OAuth provider itself, which aborted the active login and left the web login dialog stuck polling an empty flow after the user authorized in the browser. Scope invalidation to providers that were removed or had their config changed, so an in-flight login for an unaffected provider completes normally.
Context injections can now return either plain reminder text or pre-built content parts, with turn-boundary state exposed to providers instead of the cadence option.
…into kimi-code-v2
Replace the standalone HookEngine class with an App-scope IExternalHooksRunnerService that owns loading (config + plugin.enabledHooks()) and matching/running hooks. The Agent- and Session-scope external-hooks adapters now just observe their hook slots and inject the shared runner, so the duplicated per-adapter engine lifecycle (loadDynamicHooks / reload / ready gating / plugin.onDidReload) goes away. - Add src/app/externalHooksRunner/ with the contract, App-scope impl, and a pure runner module (indexHooks / runMatchedHooks / blockDecision). - Drop public HookEngine, HookEngineTriggerArgs, HookEngineOptions, and the ExternalHooksServiceOptions escape hatch; move HookEngine run/match logic into the runner. - Register externalHooksRunner at L6 and export it from the package index. - Migrate tests to a real runner built by makeHookRunner() and the externalHookServices() harness override; split engine.test.ts traits into externalHookRunner.test.ts.
IAgentContextSizeService.getStatus() becomes get(start?, end?) returning { size, measured, estimated } where size = measured + estimated. start/end follow Array.prototype.slice semantics (default whole context, negative indices count from the end, inverted range is empty). Update consumers, the context:status action binding, tests, and the edge-exposure cheatsheet.
…imports - delete per-directory index.ts barrel files across src/ submodules - update src and test imports to reference concrete module files directly - rename a few index.ts entry files to named modules (migration.ts, providers.ts, builtin.ts) - rewire src/index.ts to export from concrete modules instead of directory barrels - add patch changeset noting the production-build fix
- rename packages/server-v2 to packages/kap-server and update every @moonshot-ai/server-v2 reference across apps, packages, flake.nix, and build scripts - remove the experimental `kimi v2` CLI prefix and its tests from the apps/kimi-code main entry - add legacy BackgroundTask protocol types and the `blocked` turn interrupt reason for cross-engine compatibility
commit: |
- add `activity` domain: `IAgentActivityService` (Agent turn lane machine), `ISessionActivityKernel` (Session admission, PR1 placeholder), and the `ActivityLease` that owns the turn `AbortSignal` - turnService launches and cancels through the kernel lease; `Turn` now exposes `signal` instead of `abortController` - agentLifecycle.remove drives `beginDisposal`/`settled` and waits for the in-flight turn to drain before releasing the agent scope - add `activity.*` error codes; deprecate `turn.agent_busy` in favor of `activity.agent_busy`
These four legacy session actions were thin delegations to the native v2 services (ISessionLifecycleService.fork/archive, IAgentFullCompactionService.begin, IAgentRPCService.cancel) with no v1-only projection to centralize. Drop them from ISessionLegacyService and call the native services directly from the kap-server sessions route. updateProfile, createChild, listChildren, undo and status stay in the adapter since they carry real v1 adaptation logic.
- add native v2 print runner (v2/run-v2-print.ts) that consumes agent-core-v2 DI services and awaits Turn.result directly - extract shared print-mode rendering into prompt-render.ts for v1 and v2 - remove the V2PromptHarness/V2Session shim and v2->v1 event translation - decouple initializeCliTelemetry from PromptHarness (homeDir/auth/track) - add IAgentPromptLegacyService.submitAndSettle for authoritative completion
- make IAgentPromptService.undo throw session.undo_unavailable with a structured
reason; move the precheck into contextMemory
- add ISessionLifecycleService.createChild (fork + child markers) and
ISessionIndex.list({ childOf })
- slim ISessionLegacyService to updateProfile/status (drop createChild,
listChildren, undo)
- rewire kap-server session routes to the native services and map
SESSION_UNDO_UNAVAILABLE
- run-v2-print: use core ITelemetryService + CloudAppender instead of kimi-telemetry; remove kimi-code-sdk import (auth via IOAuthToolkit, config path from bootstrap, hook result via structural type) - prompt-render: replace SDK HookResultEvent with a structural type so the shared renderer does not depend on the v1 SDK event shape - telemetry: revert initializeCliTelemetry to its original signature now that v2 no longer calls it; keep v1 callers and assertions untouched - update run-prompt and v2-run-print tests for the new wiring
- implement SessionActivityKernel lane machine (restoring→active⇄quiescing→closing→disposed) with admission table, atomic quiesce+drain, beginClosing/settled, markActive - start AgentActivityService lane at initializing; add markReady driven by agentLifecycle.create after bootstrap - project LaneModel + EventBus facts into structured AgentActivitySnapshot (ActivityModel / setActivitySnapshot Op) with pending-approval and active-tool-call sets; emit agent.activity.updated - add IAgentTurnService.launchWithLease; goal continuation acquires the lane before appending its prompt - resolve pending interactions on turn.ended to avoid stranded awaiting_approval - fullCompaction registers a background activity and checks the activity lane - extract contextMemory publishSplice / isFullyUndoable / recoverFoldedLength helpers - kap-server: map activity snapshot into legacy status and sessionEventBroadcaster
…into kimi-code-v2
…into kimi-code-v2
…into kimi-code-v2
- add KIMI_PRINT_V2_ENV / isPrintV2Enabled so `kimi -p` routes to the native agent-core-v2 runner through its own switch - keep `kimi server run` server-v2 routing on isKimiV2Enabled (KIMI_CODE_EXPERIMENTAL_FLAG), decoupling the two - update print-mode tests and comments to reference the new switch
- resolve the effective `-p` format via resolveOutputFormat: the --output-format flag wins, then KIMI_MODEL_OUTPUT_FORMAT (prompt mode only), then text - ignore the env outside prompt mode and reject invalid values eagerly through the friendly validation path - apply the resolver on both the v1 and v2 print runners
Drop the KIMI_CRON_NO_JITTER / KIMI_CRON_NO_STALE notes from the CronCreate and CronList descriptions and the MAX_SKILL_QUERY_DEPTH sentence from the Skill description, matching agent-core (v1) where these were trimmed from the model-facing text in #1102. Code behavior is unchanged; the env bypasses and the depth cap still exist in both implementations. ULID/8-hex wording is left as-is for now.
…into kimi-code-v2
CronDelete and CronList descriptions now describe the task id as a ULID only, removing the "(or legacy 8-hex)" qualifier from the model-facing text. Code and tests are unchanged.
Move every file under test/ so its path mirrors the corresponding file under src/ one-to-one (agent/, session/, app/, os/, persistence/, _base/, activity/, wire/), and rename test files to match the basename of the source file they cover. Test-only infrastructure with no src counterpart (harness, snapshot, lint, dep-graph, tools/fixtures) stays at the top level. Rewrite imports after the move: src references use the #/ alias, while test-to-test and cross-package relative imports are recomputed for the new locations. No behavior changes.
Related Issue
N/A — integration PR that lands the long-lived
kimi-code-v2branch; see Problem below.Problem
The v2 line — the DI × Scope based
agent-core-v2engine, thekap-serverthat hosts it, and theminidbread model — has been built up on the long-livedkimi-code-v2integration branch. This PR merges that branch intomain.The v2 engine and server are not the default runtime yet. Both the
kimi -pprompt path andkimi server runroute to v2 only whenKIMI_CODE_EXPERIMENTAL_FLAGis set, and the v2 module graph is lazy-imported so it stays off the default path. With the flag unset, the CLI keeps the v1 engine and@moonshot-ai/server.What changed
Scope: 1,207 files, +192,653 / −285. The bulk is three new packages; everything else is CLI wiring, e2e coverage, skills, and small v1 touch-ups.
1. agent-core-v2: the new DI × Scope engine (
packages/agent-core-v2, +146k, 872 files)agent-core-v2package: a DI scope engine with an explicit agent / session lifecycle.ReplayTimelineModel;IEventBusandOp.toEventalongsidewire.signal; context writes routed through ops and declared tool delivery.wire.jsonl); flattened agent hierarchy with swarm lifted to session.Modelgod-object and protocol domains; kosong vendored as the internalllmProtocol/kosongimplementation (drops the@moonshot-ai/kosongand@moonshot-ai/kaosdependencies).rglocator/runner, AGENTS.md hierarchy loading.2. kap-server: the v2 server (
packages/kap-server, +26k, 139 files)@moonshot-ai/kap-serverpackage — the Kimi Code server backed byagent-core-v2(codenamed "server-v2").agent-core-v2sessions over REST (/api/v1, ~25 route modules) and WebSocket (/api/v1/wswith seq/epoch watermark and resync), and serves the web assets./openapi.jsonvia@fastify/swagger, and v2 session export (diagnostic zip archives).before_idpagination cursor, treat loopback origins as same-origin for WS upgrade, and align MCP media output with v1.3. minidb: embedded read model (
packages/minidb, +13k, 77 files)@moonshot-ai/minidbpackage — a pure-Node.js embedded KV database (Redis-style in-memory KV with SQLite-style WAL/snapshot persistence, secondary indexes, TTL), used as the session-index read model.4. CLI wiring (
apps/kimi-code, +762, 19 files)kimi -pandkimi server runselect v2 vs. v1 viaKIMI_CODE_EXPERIMENTAL_FLAG(lazy import); v1 stays the default.cli/v2/*) and theprompt-sessionabstraction shared by both engines; update TUI adapters to handle v2 events.5. Tooling, e2e and docs
packages/server-e2e: typed v2ServerClientSDK with a drift test and e2e coverage..agents/skills: add theagent-core-devandwrite-testsskills plus other skill updates; add the dependency-graph dev viewer.GOAL.md: design doc for the goal-mode feature split.packages/protocol,packages/acp-adapter,packages/agent-core,packages/server,packages/node-sdk,apps/kimi-web, thehash-importsbuild loaders,flake.nix, and changesets.Checklist
gen-changesetsskill, or this PR needs no changeset.gen-docsskill, or this PR needs no doc update.